﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using BCCommon.Enums;
using BCCommon.Extensions;
using BCData.MakeStaticPagingComponent.SystemServiceListing;
using BCEntity.MakeStaticPagingComponent.PageTemplate;
using BCEntity.MakeStaticPagingComponent.SystemServiceListing;

namespace BCService.MakeStaticPagingComponent.PageTemplateSerialize.SerializeMethod
{
    public class SerializeMethodService : ISerializeMethodService
    {
        private readonly IApplicationContextService applicationContextService;
        private readonly ISystemServiceListingData systemServiceListingData;
        public SerializeMethodService(IApplicationContextService applicationContextService, ISystemServiceListingData systemServiceListingData)
        {
            this.applicationContextService = applicationContextService;
            this.systemServiceListingData = systemServiceListingData;
        }

        #region 解析页面定义数据
        /// <summary>
        /// 解析页面定义数据
        /// </summary>
        /// <param name="pageTemplateEntity">页面模版信息</param>
        /// <param name="inputParams">传入参数</param>
        /// <returns></returns>
        public void ParsePageDefineData(PageTemplateEntity pageTemplateEntity, Dictionary<string, object> inputParams)
        {
            string pageDefine = pageTemplateEntity.PageDefine;
            if (string.IsNullOrWhiteSpace(pageDefine))
            {
                return;
            }
            while (pageDefine.Any(p => p == ' '||p == '\r'||p == '\n'))
            {
                pageDefine = pageDefine.Replace(" ", "").Replace("\n", "").Replace("\r", "").Replace("\r\n", "");
            }

            if (pageTemplateEntity.IsPagingListPage)
            {
                inputParams.Add("$$pageDataCount", pageTemplateEntity.TotalPageCount);
                inputParams.Add("$$pageIndex", pageTemplateEntity.CurrentlyPageNumber);
                inputParams.Add("$$pageSize", pageTemplateEntity.ListSize);
            }

            Regex systemDefineTagRegex = new Regex("[$]{2}[^!@#$&*\\s\n]+");
            while (systemDefineTagRegex.IsMatch(pageDefine))
            {
                string variable = systemDefineTagRegex.Match(pageDefine).Value;
                if(inputParams.TryGetValue(variable,out object systemDefineData))
                {
                    pageDefine = pageDefine.Replace(variable, systemDefineData.ToString());
                }
                else
                {
                    throw new ArgumentException(string.Format("页面数据定义中存在非系统定义数据标签,解析页面定义数据失败!标签名称：{0}", variable));
                }
            }
            
            Dictionary<string, string> fixDic = new Dictionary<string, string>();
            string[] rows = pageDefine.Split(";",StringSplitOptions.RemoveEmptyEntries);
            Regex regex = new Regex("[&]{2}\\w*\\s*[=]\\s*(([&$#]{2}[a-zA-Z_0-9]+([(](([\"\']?[a-zA-Z_0-9]+[\"\']?[,]?)*|((\\d +)[,]?)*|([\\d]*[.][\\d]+[,]?)*)*[)])?)|(\\w+[(](([\"\']?[a-zA-Z_0-9]+[\"\']?[,]?)*|((\\d+)[,]?)*|([\\d]*[.][\\d]+[,]?)*)*[)])?|([\"\']?[a-zA-Z_0-9]+[\"\']?)*|(\\d*[.]?\\d*)*|([\\d]*[.][\\d]+[,]?)*)?");
            foreach (var item in rows)
            {
                if (!regex.IsMatch(item))
                {
                    throw new ArgumentException(string.Format("预定义定义数据不正确，预定义数据内容：{0}", item));
                }
                string[] define = item.Split('=');
                if (inputParams.TryGetValue(define[0], out object result))
                {
                    throw new ArgumentException(string.Format("重复定义变量：{0}", define[0]));
                }
                Regex paramsRegex = new Regex("(\\w+)[(](([\"\']?[&$#!@a-zA-Z_0-9]+[\"\']?[,]?)*|((\\d+)[,]?)*|([\\d]*[.][\\d]+[,]?)*)*[)]");
                if (paramsRegex.IsMatch(define[1]))
                {
                    string[] prefix = new string[] { "&&", "$$", "@@", "##", "**", "!!" };
                    if (define[1].Substring(0, 2).In(prefix))
                    {
                        if (!inputParams.TryGetValue(define[1].Trim(), out object referenceData))
                        {
                            fixDic.Add(define[0], define[1].Trim());
                        }
                        else
                        {
                            inputParams.TryAdd(define[0], referenceData);
                        }
                    }
                    else
                    {
                        inputParams.TryAdd(define[0], this.GetValue(define[1], inputParams));
                    }
                }
                else
                {
                    inputParams.TryAdd(define[0], define[1]);
                }
            }
            if (fixDic.Any())
            {
                foreach (KeyValuePair<string, string> keyValue in fixDic)
                {
                    if (!inputParams.TryGetValue(keyValue.Value, out object referenceData))
                    {
                        inputParams.Add(keyValue.Key, string.Empty);
                    }
                    else
                    {
                        inputParams.Add(keyValue.Key, referenceData);
                    }
                }
            }
            
        }
        #endregion

        #region 获取预定义变量值
        /// <summary>
        /// 获取预定义变量值
        /// </summary>
        /// <param name="input">预定义表达式输入内容</param>
        /// <param name="inputParams">传入参数</param>
        /// <returns></returns>
        private object GetValue(string input, Dictionary<string, object> inputParams)
        {
            Regex regex = new Regex("(\\w+)[(](([\"\']?[@a-zA-Z_0-9]+[\"\']?[,]?)*|((\\d+)[,]?)*|([\\d]*[.][\\d]+[,]?)*)*[)]");
            if (regex.IsMatch(input))
            {
                string serviceName = regex.Match(input).Groups[1].Value;
                Regex paramsRegex = new Regex("(?<=(?:[(]))[^)]*(?=([)]))");
                if (!paramsRegex.IsMatch(input))
                {
                    throw new ArgumentException(string.Format("解析定义表达式检查事错误，表达式定义不正确！表达式名称：{0}", serviceName));
                }
                string value = paramsRegex.Match(input).Value;
                while (value.IndexOf(" ") > -1)
                {
                    value = value.Replace(" ", "");
                }
                string[] strParams = value.Split(',');
                List<object> parameterArr = new List<object>();
                string[] prefix = new string[] { "&&", "$$", "@@", "##", "**", "!!" };
                for (int i = 0; i < strParams.Length; i++)
                {
                    if (strParams[i].Length > 2)
                    {
                        if (strParams[i].Substring(0, 2).In(prefix))
                        {
                            Regex referenceObjRegex = new Regex("([&]{2}\\w+)");
                            Regex referenceValueObjRegex = new Regex("([@]{2}\\w+)");
                            if (referenceObjRegex.IsMatch(strParams[i]))
                            {
                                string referenceObjName = referenceObjRegex.Match(strParams[i]).Value;
                                if (!inputParams.TryGetValue(referenceObjName.Trim(), out object referenceData))
                                {
                                    throw new ArgumentException(string.Format("预定义定义数据不存在，预定义数据内容：{0}", referenceObjName));
                                }
                                string referenceValueObjName = referenceValueObjRegex.Match(strParams[i]).Value;
                                object result = GetDefineObjValue(referenceValueObjName, referenceData);
                                parameterArr.Add(result);
                            }
                            else if (referenceValueObjRegex.IsMatch(strParams[i]))
                            {
                                string referenceValueObjName = referenceValueObjRegex.Match(strParams[i]).Value;
                                if (!inputParams.TryGetValue("&&ContentResult", out object referenceData))
                                {
                                    throw new ArgumentException(string.Format("预定义定义数据不存在，预定义数据内容：{0}", "&&ContentResult"));
                                }
                                object result = GetDefineObjValue(referenceValueObjName, referenceData);
                                parameterArr.Add(result);
                            }
                            else
                            {
                                if (!inputParams.TryGetValue(strParams[i], out object referenceData))
                                {
                                    throw new ArgumentException(string.Format("预定义定义数据不存在，预定义数据内容：{0}", strParams[i]));
                                }
                                parameterArr.Add(referenceData);
                            }
                        }
                        else
                        {
                            parameterArr.Add(strParams[i]);
                        }
                    }
                    else
                    {
                        parameterArr.Add(strParams[i]);
                    }
                }
                SystemServiceListingEntity systemServiceListingEntity = this.systemServiceListingData.Get(serviceName);
                if (systemServiceListingEntity == null)
                {
                    throw new ArgumentException(string.Format("{0} 服务不存在", serviceName));
                }

                return this.GetServiceMethodExecutionResult(systemServiceListingEntity, parameterArr);
            }
            else
            {
                if (input.Contains("$$"))
                {
                    return inputParams[input];
                }
                return input;
            }
        }
        #endregion
        /// <summary>
        /// 解析标签
        /// </summary>
        /// <param name="tagName">标签名称</param>
        /// <param name="obj">结果对象</param>
        /// <returns></returns>
        private object GetDefineObjValue(string tagName, object obj)
        {
            object value = null;
            string tagValue = tagName.Replace("@@", "");
            if (obj != null)
            {
                Type type = obj.GetType();
                if (type.IsClass && !type.IsGenericType && type.GetProperty(tagValue) != null)
                {
                    PropertyInfo[] properties = type.GetProperties();
                    foreach (PropertyInfo property in properties)
                    {
                        if (property.Name == tagValue)
                        {
                            value = property.GetValue(obj, null);
                        }
                    }
                    return value;
                }
            }
            return "";
        }
        #region 获取服务方法执行结果
        /// <summary>
        /// 获取服务方法执行结果
        /// </summary>
        /// <param name="systemServiceListingEntity">服务方法列表信息</param>
        /// <param name="parameterArr">参数列表</param>
        /// <returns></returns>
        private object GetServiceMethodExecutionResult(SystemServiceListingEntity systemServiceListingEntity, List<object> parameterArr)
        {
            //序列化服务调用参数对象
            Dictionary<string, object> dictionary = new Dictionary<string, object>();
            if (!string.IsNullOrWhiteSpace(systemServiceListingEntity.ParamsText))
            {
                string[] paramsTemplate = systemServiceListingEntity.ParamsText.Replace("(", "").Replace(")", "").Split(',');

                if (paramsTemplate.Length != parameterArr.Count)
                {
                    throw new ArgumentException(string.Format("服务方法型参参数与实参参数数量不相同！表达式名称：{0}", systemServiceListingEntity.MethodName));
                }
                for (int i = 0; i < paramsTemplate.Length; i++)
                {
                    string paramsName = paramsTemplate[i].Trim().Split(' ')[1].Trim();
                    dictionary.Add(paramsName, parameterArr[i]);
                }
            }


            //开始构建动态服务
            Type type = Type.GetType(systemServiceListingEntity.ServiceName);

            ConstructorInfo firstConstructor = type.GetTypeInfo().GetConstructors().FirstOrDefault();
            //获取构造参数列表最多的构造方法
            foreach (var constructor in type.GetTypeInfo().GetConstructors())
            {
                if (constructor.GetParameters().Length > firstConstructor.GetParameters().Length)
                {
                    firstConstructor = constructor;
                }
            }
            //提取构造参数
            IEnumerable<object> constructorParameters = firstConstructor.GetParameters().Select(p => this.applicationContextService.RequestServices.GetService(p.ParameterType));
            //构建服务实例
            var service = Activator.CreateInstance(type, constructorParameters.ToArray());
            //构建服务方法
            MethodInfo method = type.GetMethod(systemServiceListingEntity.MethodName);
            if (method == null)
            {
                throw new ArgumentException("系统不存在此方法，请检查服务命名空间及方法名称是否正确！");
            }
            //提取服务方法调用参数列表
            ParameterInfo[] parameters = method.GetParameters();
            List<object> requestParams = new List<object>();
            if (parameters.Any())
            {
                if (!parameterArr.Any())
                {
                    foreach (ParameterInfo parameter in parameters)
                    {
                        if (dictionary.TryGetValue(parameter.Name, out object value))
                        {
                            requestParams.Add(Convert.ChangeType(value, parameter.ParameterType));
                        }
                        else
                        {
                            if (parameter.ParameterType.Name.Equals("String"))
                            {
                                requestParams.Add("");
                            }
                            else if (parameter.ParameterType.IsGenericType && parameter.ParameterType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
                            {
                                requestParams.Add(null);
                            }
                            else
                            {
                                requestParams.Add(parameter.RawDefaultValue);
                            }
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < dictionary.Count; i++)
                    {
                        var obj = dictionary.ElementAt(i);
                        if (parameters[i].ParameterType.Name == "Nullable`1")
                        {
                            if (obj.Value.ToString().Trim().ToLower() != "null" && obj.Value.ToString().Trim() != "")
                            {
                                if (parameters[i].ParameterType.GenericTypeArguments.Length > 0)
                                {
                                    requestParams.Add(Convert.ChangeType(obj.Value, parameters[i].ParameterType.GenericTypeArguments[0]));
                                }
                            }
                            else
                            {
                                requestParams.Add(null);
                            }
                        }
                        else
                        {
                            if (obj.Value.ToString().Trim() == "null")
                            {
                                if (parameters[i].ParameterType.Name == "String")
                                {
                                    requestParams.Add("");
                                }
                                else
                                {
                                    requestParams.Add(null);
                                }
                            }
                            else if (obj.Value.ToString().IndexOf("\"") > -1)
                            {
                                string value = obj.Value.ToString();
                                while (value.IndexOf("\"") > -1)
                                {
                                    value = obj.Value.ToString().Replace("\"", "");
                                }
                                if (string.IsNullOrWhiteSpace(value))
                                {
                                    if (parameters[i].ParameterType.Name == "String")
                                    {
                                        requestParams.Add("");
                                    }
                                    else
                                    {
                                        requestParams.Add(null);
                                    }
                                }
                                else
                                {
                                    requestParams.Add(Convert.ChangeType(value, parameters[i].ParameterType));
                                }
                            }
                            else
                            {
                                requestParams.Add(Convert.ChangeType(obj.Value, parameters[i].ParameterType));
                            }
                        }
                    }
                }
            }
            object result = method.Invoke(service, requestParams.ToArray());
            return result;
        }
        #endregion
    }
}
